package br.com.foxinline.servico;

import br.com.foxinline.enums.Caracterizacao;
import br.com.foxinline.enums.Comando;
import br.com.foxinline.enums.Relatorio;
import br.com.foxinline.enums.SituacaoImovel;
import br.com.foxinline.enums.TipoDocumento;
import br.com.foxinline.enums.UsoImovel;
import br.com.foxinline.generico.ServicoGenerico;
import br.com.foxinline.modelo.*;
import br.com.foxinline.util.ArquivoUtilitario;
import br.com.foxinline.util.Extenso;
import br.com.foxinline.util.GrupoUtilitario;
import java.beans.Transient;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.faces.context.FacesContext;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import javax.servlet.ServletContext;

/**
 *
 * @author ely
 */
@Stateless
@DeclareRoles(GrupoUtilitario.ADMINISTRADOR)
public class ImovelServico extends ServicoGenerico<Imovel> {

    @EJB
    ProprietarioServico proprietarioServico;
    @EJB
    private IptuServico iptuServico;
    @EJB
    AnexoServico anexoServico;
    @EJB
    BairroServico bairroServico;
    @EJB
    PrefeituraServico prefeituraServico;
    private Long quantidadeRegistrosResults;
    private String whereImovelAtivo = " and i.ativo = true and i.inscricaoCanceladaPorDesmembramento = false ";
    private String linhasQuebradas = "em linhas quebradas ";
    private Boolean imovelComNumero;
    private Boolean imovelComCroqui;
    private Boolean imovelComAnexo;
    private Boolean imovelComProprietario;
    private Boolean imovelComDimensao;
    private Boolean imovelComConfrontacao;
    private Boolean imovelIsentoIPTU;
    private Boolean imovelIsentoSTU;
    private List<Bairro> bairros;
    private List<Long> bairrosId;
    private List<Integer> imovelQuadras;
    private String orderBy;
    private Boolean imovelComCoordenadaConfrontacao;

    public ImovelServico() {
        super(Imovel.class);
    }

    @Override
    public void save(Imovel entity) {

        if (entity.getAnnex() != null) {
            if (entity.getAnnex().isEmpty()) {
                entity.setAnnex(null);
            } else {

                for (Anexo anexo : entity.getAnnex()) {
                    anexo.setImovel(entity);
                }
            }
        }

        if (entity.getAnnexCroquis() != null) {
            if (entity.getAnnexCroquis().isEmpty()) {
                entity.setAnnexCroquis(null);
            } else {
                for (Anexo anexo : entity.getAnnexCroquis()) {
                    anexo.setImovelCroqui(entity);
                }
            }
        }

        if (entity.getProprietarios() != null && entity.getProprietarios().isEmpty()) {
            entity.setProprietarios(null);
        }
        if (entity.getCoordenadas() != null && entity.getCoordenadas().isEmpty()) {
            entity.setCoordenadas(null);
        }
        if (entity.getMoradores() != null) {
            if (entity.getMoradores().isEmpty()) {
                entity.setMoradores(null);
            } else {
                for (Proprietario proprietario : entity.getMoradores()) {
                    proprietario.setEndereco(entity.getEnderecoImovel());
                }
            }
        }

        if (entity.getEnderecoImovel() != null && entity.getEnderecoImovel().getBairro() != null && !entity.getEnderecoImovel().getBairro().isEmpty()) {

            List<Bairro> bairros = bairroServico.autoComplete(entity.getEnderecoImovel().getBairro());

            if (!bairros.isEmpty()) {
                entity.getEnderecoImovel().setBairroDne(bairros.get(0));
            }
        }

        if (entity.getEnderecoCorrespondencia() != null && entity.getEnderecoCorrespondencia().getBairro() != null && !entity.getEnderecoCorrespondencia().getBairro().isEmpty()) {

            List<Bairro> bairros = bairroServico.autoComplete(entity.getEnderecoCorrespondencia().getBairro());

            if (!bairros.isEmpty()) {
                entity.getEnderecoCorrespondencia().setBairroDne(bairros.get(0));
            }
        }

        entity.setCreateAt(new Date());
        entity.setPagaIptu(entity.getIsentoIptu());

        super.save(entity);
    }

    @Override
    public void update(Imovel entity) {
        if (entity.getAnnex() != null && entity.getAnnex().isEmpty()) {

            entity.setAnnex(null);

        } else if (entity.getAnnex() != null) {
            for (Anexo anexo : entity.getAnnex()) {
                anexo.setImovel(entity);
            }
        }

        if (entity.getAnnexCroquis() != null && entity.getAnnexCroquis().isEmpty()) {

            entity.setAnnexCroquis(null);

        } else if (entity.getAnnexCroquis() != null) {

            for (Anexo anexo : entity.getAnnexCroquis()) {
                anexo.setImovelCroqui(entity);
            }
        }

        if (entity.getProprietarios() != null && entity.getProprietarios().isEmpty()) {
            entity.setProprietarios(null);
        }
        if (entity.getCoordenadas() != null && entity.getCoordenadas().isEmpty()) {
            entity.setCoordenadas(null);
        }
        if (entity.getMoradores() == null || (entity.getMoradores() != null && entity.getMoradores().isEmpty())) {
            entity.setMoradores(null);
        } else {
            for (Proprietario morador : entity.getMoradores()) {
                morador.setEndereco(entity.getEnderecoImovel());
            }
        }

        if (entity.getIsentoIptu() != null) {
            entity.setPagaIptu(!entity.getIsentoIptu());
        }
        super.update(entity);
        updateAnexos(entity);
    }

    @Override
    public void updateAnexos(Imovel p) {
        p.setAnnex(lstAnnexs(p));
        p.setAnnexCroquis(lstAnnexCroqui(p));
        super.updateAnexos(p);
    }

    @Override
    @RolesAllowed(GrupoUtilitario.ADMINISTRADOR)
    public void delete(Imovel entity) {
        super.delete(entity);
    }

    public List<Proprietario> lstProprietario(Imovel imovel) {
        String sql = "SELECT p FROM Imovel i JOIN i.proprietarios p WHERE i.id = :id ORDER BY i.id";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", imovel.getId());
        return (List<Proprietario>) query.getResultList();
    }

    public List<Coordenada> lstCoordenadas(Imovel imovel) {
        String sql = "SELECT c FROM Imovel i JOIN i.coordenadas c WHERE i.id  = :id ORDER BY c.id";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", imovel.getId());
        return (List<Coordenada>) query.getResultList();
    }

    public List<Coordenada> lstCoordenadasDimensoes(Imovel imovel) {
        String sql = "SELECT c FROM Imovel i JOIN i.coordenadasDimensoes c WHERE i.id = :id ORDER BY c.id";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", imovel.getId());
        return (List<Coordenada>) query.getResultList();
    }

    public List<Anexo> lstAnnexs(Imovel imovel) {
        String sql = "SELECT a FROM Imovel i JOIN i.annex a WHERE i.id = :id and a.ativo = true ORDER BY a.id ";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", imovel.getId());
        return (List<Anexo>) query.getResultList();
    }

    public List<Anexo> lstAnnexCroqui(Imovel imovel) {
        String sql = "SELECT a FROM Imovel i JOIN i.annexCroquis a WHERE i.id = :id and a.ativo = true order by a.id";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", imovel.getId());
        return (List<Anexo>) query.getResultList();
    }

    public List<Imovel> findImovel(Imovel imovel) {
        String sql = "SELECT i FROM Imovel i  WHERE i.id = :id " + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", imovel.getId());
        return (List<Imovel>) query.getResultList();
    }

    public List<Imovel> findImovelProprietario(Proprietario proprietario) {
        String sql = "SELECT i FROM Imovel i JOIN i.proprietarios p WHERE p = :p " + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("p", proprietario);
        return (List<Imovel>) query.getResultList();
    }

    /*
     * Traz um único imóvel do proprietário
     */
    public Imovel findProprietario(Proprietario proprietario) {
        String sql = "SELECT i FROM Imovel i JOIN i.proprietarios p WHERE p = :p " + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("p", proprietario);
        return (Imovel) query.getSingleResult();
    }

    public List<Imovel> imovelPendente(String grupo, Bairro bairro, String proprietario, String documentos) {

        String sql = "SELECT i FROM Imovel i ";

        if (bairro != null && bairro.getId() != null) {
            sql += "JOIN i.enderecoImovel ei ";
        }

        sql += " WHERE ";

        if ((proprietario == null || proprietario.equals(""))
                && (documentos == null || documentos.equals(""))) {
            sql += " (i.proprietarios is empty "
                    + "or i.annex is empty) and";
        } else {
            if (proprietario != null && !proprietario.equals("")) {
                sql += "i.proprietarios is empty and ";
            }
            if (documentos != null && !documentos.equals("")) {
                sql += "i.annex is empty and ";
            }
        }

        if (bairro != null && bairro.getId() != null) {
            sql += " lower(ei.bairroDne.nome) like lower(:bairro) and";
        }

        sql += " i.groupCreate like :groupCreate order by i.groupCreate ASC";

        Query query = getEntityManager().createQuery(sql);
        query.setParameter("groupCreate", "%" + grupo + "%");

        if (bairro != null && bairro.getId() != null) {
            query.setParameter("bairro", "%" + bairro.getNome() + "%");
        }

        return query.getResultList();
    }

    public List<Imovel> imovelPendenteIPTU(Bairro bairro, String filtro) {

        String sql = "SELECT i FROM Imovel i JOIN i.dimensoes d ";

        if (bairro != null && bairro.getId() != null) {
            sql += "JOIN i.enderecoImovel ei";
        }

        sql += " WHERE ";

        sql += filtro;

        if (bairro != null && bairro.getId() != null) {
            sql += " and lower(ei.bairro) like lower(:bairro) ";
        }


        Query query = getEntityManager().createQuery(sql);

        if (bairro != null && bairro.getId() != null) {
            query.setParameter("bairro", "%" + bairro.getNome() + "%");
        }

        return query.getResultList();
    }

    public List<Imovel> imovelPendente(String grupo) {

        String sql = "SELECT i FROM Imovel i "
                + "WHERE (i.proprietarios is empty "
                + "or i.annex is empty "
                + " ) and i.groupCreate like :groupCreate " + this.whereImovelAtivo
                + "order by i.groupCreate ASC";

        Query query = getEntityManager().createQuery(sql);
        query.setParameter("groupCreate", "%" + grupo + "%");

        return query.getResultList();
    }

    public List<Imovel> findImovelInscCadastral(String inscricaoImovel) {
        Imovel imovel = new Imovel();

        String[] str = inscricaoImovel.split("\\.");

        imovel.setInscricaoCadastralD(Integer.parseInt(str[0]));
        imovel.setInscricaoCadastralS(Integer.parseInt(str[1]));
        imovel.setInscricaoCadastralQuadra(Integer.parseInt(str[2]));
        imovel.setInscricaoCadastralLote(Integer.parseInt(str[3]));
        imovel.setInscricaoCadastralUnid(Integer.parseInt(str[4]));

        String sql = "SELECT i FROM Imovel i where ";

        sql += " i.inscricaoCadastralD = :d and ";
        sql += " i.inscricaoCadastralS = :s and ";
        sql += " i.inscricaoCadastralQuadra = :q and ";
        sql += " i.inscricaoCadastralLote = :l and ";
        sql += " i.inscricaoCadastralUnid = :u and ";

        sql += "i.ativo = true ";
        sql += " and i.comando = :comando ";
        sql += "Order by i.id ASC";

        Query query = getEntityManager().createQuery(sql);

        if (imovel.getInscricaoCadastralD() != null) {
            query.setParameter("d", imovel.getInscricaoCadastralD());
        }

        if (imovel.getInscricaoCadastralS() != null) {
            query.setParameter("s", imovel.getInscricaoCadastralS());
        }

        if (imovel.getInscricaoCadastralQuadra() != null) {
            query.setParameter("q", imovel.getInscricaoCadastralQuadra());
        }

        if (imovel.getInscricaoCadastralUnid() != null) {
            query.setParameter("u", imovel.getInscricaoCadastralUnid());
        }

        if (imovel.getInscricaoCadastralLote() != null) {
            query.setParameter("l", imovel.getInscricaoCadastralLote());
        }

        if (imovel.getInscricaoCadastralLote() != null) {
            query.setParameter("l", imovel.getInscricaoCadastralLote());
        }

        query.setParameter("comando", Comando.INCLUSAO);

        return query.getResultList();
    }

    public void reportsAtlasMobileRegImovel(HashMap parametros, Imovel imovel, Proprietario proprietario, Endereco endereco, boolean imprimirAnexos) {

        imovel.setProprietarios(new ArrayList<Proprietario>());
        imovel.getProprietarios().add(proprietario);
        imovel.setEnderecoImovel(endereco);

        List<Imovel> imoveis = find(imovel, null, null);

        relatorioBCI(parametros, imoveis, imprimirAnexos);
    }

    public void relatorioBCI(HashMap parametros, List<Imovel> regImovel, boolean imprimirAnexos) {

        for (Imovel imovel : regImovel) {

            List<Anexo> anexosRemover = new ArrayList<Anexo>();

            for (Anexo a : imovel.getAnnexCroquis()) {
                InputStream imgInputStream = null;
                if (a != null) {
                    try {

                        if (a.getNome() != null && !a.getNome().isEmpty() && ArquivoUtilitario.getFileSuffix(a.getNome()).equals("pdf")) {
                            anexosRemover.add(a);
                            continue;
                        }

                        if (a.getUrl() != null && a.getNome() != null) {
                            Path path = Paths.get(a.getUrl().concat(a.getNome()));

                            if (path != null) {
                                imgInputStream = new ByteArrayInputStream(Files.readAllBytes(path));
                            }

                        } else {
                            imgInputStream = new ByteArrayInputStream(a.getArquivo());
                        }

                    } catch (IOException ex) {
                        System.err.println(ex);
                        Logger.getLogger(ImovelServico.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

                a.setCroquiRelatorio(imgInputStream);
            }

            imovel.getAnnexCroquis().removeAll(anexosRemover);
            anexosRemover.clear();

            if (imprimirAnexos) {

                if (imovel.getAnnex() == null || imovel.getAnnex().isEmpty()) {
                    imovel.setAnnex(lstAnnexs(imovel));
                }

                for (Anexo a : imovel.getAnnex()) {
                    InputStream imgInputStream = null;
                    if (a != null) {
                        try {

                            if (a.getNome() != null && !a.getNome().isEmpty() && ArquivoUtilitario.getFileSuffix(a.getNome()).equals("pdf")) {
                                anexosRemover.add(a);
                                continue;
                            }
                            if (a.getUrl() != null && a.getNome() != null) {
                                Path path = Paths.get(a.getUrl().concat(a.getNome()));

                                if (path != null) {
                                    imgInputStream = new ByteArrayInputStream(Files.readAllBytes(path));
                                }

                            } else {
                                if (a.getArquivo() != null) {
                                    imgInputStream = new ByteArrayInputStream(a.getArquivo());
                                }
                            }
                        } catch (IOException ex) {
                            System.err.println(ex);
                            Logger.getLogger(ImovelServico.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }

                    a.setCroquiRelatorio(imgInputStream);
                }
                imovel.getAnnex().removeAll(anexosRemover);
            } else {
                imovel.setAnnex(null);
            }
        }

        URL subreport = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/bci_proprietario.jasper");
        final String sub = subreport.toString().replace("bci_proprietario.jasper", "");
        parametros.put("SUBREPORT_DIR", sub);

        FacesContext facesContext = FacesContext.getCurrentInstance();
        ServletContext servletContext = (ServletContext) facesContext.getExternalContext().getContext();

        parametros.put("IMAGE_DIR", servletContext.getRealPath("/media/images/brasao.jpg"));

        RelatorioServico.genReport(parametros, regImovel, Relatorio.REPORTATLASMOBILE);

    }

    public boolean relatorioMemorialDescritivo(HashMap parametros, List<Imovel> imoveis) {

        for (Imovel imovel : imoveis) {
            imovel.setCoordenadas(lstCoordenadas(imovel));
            imovel.setProprietarios(lstProprietario(imovel));
            imovel.setAnnexCroquis(lstAnnexCroqui(imovel));

            if (imovel.getDimensoes() != null) {
                if (imovel.getDimensoes().getAreaTerreno() != null) {

                    String areaInteira = imovel.getDimensoes().getAreaTerreno().toString().substring(0, imovel.getDimensoes().getAreaTerreno().toString().lastIndexOf("."));
                    String areaDecimal = imovel.getDimensoes().getAreaTerreno().toString().substring(imovel.getDimensoes().getAreaTerreno().toString().lastIndexOf("."), imovel.getDimensoes().getAreaTerreno().toString().length());

                    Extenso extensoInteiro = new Extenso(new BigDecimal(areaInteira));
                    Extenso extensoDecimal = new Extenso(new BigDecimal(areaDecimal));

                    if (extensoInteiro != null) {

                        StringBuffer sbProprietario = new StringBuffer();

                        for (Proprietario p : imovel.getProprietarios()) {
                            sbProprietario.append(p.getNome());
                            sbProprietario.append(", ");
                        }
                        if (sbProprietario.length() != 0) {
                            sbProprietario.delete(sbProprietario.length() - 2, sbProprietario.length());
                            if (imovel.getProprietarios().size() > 1) {
                                int tam = imovel.getProprietarios().get(imovel.getProprietarios().size() - 1).getNome().length();
                                sbProprietario.replace(sbProprietario.length() - tam - 2, sbProprietario.length() - tam - 1, "e");
                            }
                        }

                        String perimetroExtenso = "";

                        if (imovel.getDimensoes().getPerimetro() != null) {

                            String perimetroInteira = imovel.getDimensoes().getPerimetro().toString().substring(0, imovel.getDimensoes().getPerimetro().toString().lastIndexOf("."));
                            String perimetroDecimal = imovel.getDimensoes().getPerimetro().toString().substring(imovel.getDimensoes().getPerimetro().toString().lastIndexOf("."), imovel.getDimensoes().getPerimetro().toString().length());

                            Extenso extensoPerimetroInteiro = new Extenso(new BigDecimal(perimetroInteira));
                            Extenso extensoPerimetroDecimal = new Extenso(new BigDecimal(perimetroDecimal));


                            if (extensoPerimetroInteiro != null) {

                                String extensoPerimetroDecimalString = extensoPerimetroDecimal != null ? "e " + extensoPerimetroDecimal.toString() + "centímetros" : "";
                                perimetroExtenso += "(" + extensoPerimetroInteiro.toString() + " metros " + extensoPerimetroDecimalString + ")";
                            }

                            imovel.setPerimeField(imovel.getDimensoes().getPerimetro().toString().replace(".", ",") + "m ");
                        } else {
                            imovel.setPerimeField("");
                        }

                        String bairro = imovel.getEnderecoImovel().getBairroDne() != null && imovel.getEnderecoImovel().getBairroDne().getNome() != null && !imovel.getEnderecoImovel().getBairroDne().getNome().isEmpty() ? imovel.getEnderecoImovel().getBairroDne().getNome() : imovel.getEnderecoImovel().getBairro();

                        String extensoDecimalString = extensoDecimal != null ? ", " + extensoDecimal.toString() + "centésimas de " : "";

                        String texto = "           Memorial descritivo de um terreno situado no município de Parnaíba, estado"
                                + " do Piauí, tendo como proprietário(a) " + sbProprietario + ", localizado no bairro "
                                + bairro
                                + ", zona Urbana da cidade, "
                                + "com uma área total de " + imovel.getDimensoes().getAreaTerreno().toString().replace(".", ",");

                        texto = texto.toUpperCase() + " m² (";

                        texto += (extensoInteiro.toString() + extensoDecimalString
                                + "metros quadrados) e um perímetro de ").toUpperCase() + " " + imovel.getPerimeField().replace("m", " m") + (perimetroExtenso + " com os "
                                + "seguintes limites e confrontações").toUpperCase();

                        imovel.setTextoField(texto);
                        imovel.setProprietarioField("" + sbProprietario);

                        if (imovel.getCoordenadasDimensoes().size() >= 3) {
                            descricaoPerimetro(imovel, extensoInteiro, extensoDecimalString);
                        }

                        if (imovel.getDimensoes().getAreaTerreno() != null) {
                            imovel.setAreaField(String.valueOf(imovel.getDimensoes().getAreaTerreno() + " m²"));
                        } else {
                            imovel.setAreaField("");
                        }

                    }

                } else {


                    StringBuffer sbProprietario = new StringBuffer();
                    for (Proprietario p : imovel.getProprietarios()) {
                        sbProprietario.append(p.getNome());
                        sbProprietario.append(" , ");
                    }
                    if (sbProprietario.length() != 0) {
                        sbProprietario.delete(sbProprietario.length() - 3, sbProprietario.length());
                        if (imovel.getProprietarios().size() > 1) {
                            int tam = imovel.getProprietarios().get(imovel.getProprietarios().size() - 1).getNome().length();
                            sbProprietario.replace(sbProprietario.length() - tam - 2, sbProprietario.length() - tam - 1, "e");
                        }
                    }

                    imovel.setProprietarioField("" + sbProprietario);

                    // Código Perímetro
                    if (imovel.getDimensoes().getPerimetro() != null) {
                        imovel.setPerimeField(String.valueOf(imovel.getDimensoes().getPerimetro() + " m²"));
                    } else {
                        imovel.setPerimeField("");
                    }

                    String texto = "           Obs : Esse Imóvel não possue uma área cadastrada, por favor atualizar os dados referentes "
                            + " a área do terreno, Imóvel -> Consulta -> selecione o imóvel clicando em editar, vá na aba de "
                            + "dimensões, digite o dado no campo área do terreno, e clique em salvar.  ";

                    imovel.setTextoField(texto);
                }
            }

            String linhaQuebrada;

            if (imovel.getFrente() != null && !imovel.getFrente().isEmpty() && imovel.getFrenteRua() != null && !imovel.getFrenteRua().isEmpty() && imovel.getFrenteMedindo() != null) {

                linhaQuebrada = imovel.getFrenteMedindoEmLinhasQuebradas() != null && imovel.getFrenteMedindoEmLinhasQuebradas() ? linhasQuebradas : "";

                String texto_frente = "Para o " + imovel.getFrente().trim() + ", limitando-se com " + imovel.getFrenteRua().trim()
                        + ", medindo " + linhaQuebrada + imovel.getFrenteMedindo().toString().trim();

                texto_frente = texto_frente.toUpperCase() + " m.";

                imovel.setFrenteField(texto_frente);
            } else {
                imovel.setFrenteField("");
            }

            if (imovel.getFundo() != null && !imovel.getFundo().isEmpty() && imovel.getFundoRua() != null && !imovel.getFundoRua().isEmpty() && imovel.getFundoMedindo() != null) {

                linhaQuebrada = imovel.getFundoMedindoEmLinhasQuebradas() != null && imovel.getFundoMedindoEmLinhasQuebradas() ? linhasQuebradas : "";

                String texto_fundo = "Para o " + imovel.getFundo().trim() + ", limitando-se com " + imovel.getFundoRua().trim()
                        + ", medindo " + linhaQuebrada + imovel.getFundoMedindo().toString().trim();

                texto_fundo = texto_fundo.toUpperCase() + " m.";
                imovel.setFundoField(texto_fundo);
            } else {
                imovel.setFundoField("");
            }

            if (imovel.getLadoDireito() != null && !imovel.getLadoDireito().isEmpty() && imovel.getLadoDireitoRua() != null && !imovel.getLadoDireitoRua().isEmpty() && imovel.getLadoDireitoMedindo() != null) {

                linhaQuebrada = imovel.getLadoDireitoMedindoEmLinhasQuebradas() != null && imovel.getLadoDireitoMedindoEmLinhasQuebradas() ? linhasQuebradas : "";

                String texto_direito = "Para o " + imovel.getLadoDireito().trim() + ", limitando-se com " + imovel.getLadoDireitoRua().trim()
                        + ", medindo " + linhaQuebrada + imovel.getLadoDireitoMedindo().toString().trim();

                texto_direito = texto_direito.toUpperCase() + " m.";

                imovel.setDireitoField(texto_direito);
            } else {
                imovel.setDireitoField("");
            }

            if (imovel.getLadoEsquerdo() != null && !imovel.getLadoEsquerdo().isEmpty() && imovel.getLadoEsquerdoRua() != null && !imovel.getLadoEsquerdoRua().isEmpty() && imovel.getLadoEsquerdoMedindo() != null) {

                linhaQuebrada = imovel.getLadoEsquerdoMedindoEmLinhasQuebradas() != null && imovel.getLadoEsquerdoMedindoEmLinhasQuebradas() ? linhasQuebradas : "";

                String texto_esquerdo = "Para o " + imovel.getLadoEsquerdo().trim() + ", limitando-se com " + imovel.getLadoEsquerdoRua().trim()
                        + ", medindo " + linhaQuebrada + imovel.getLadoEsquerdoMedindo().toString().trim();

                texto_esquerdo = texto_esquerdo.toUpperCase() + " m.";

                imovel.setEsquerdoField(texto_esquerdo);
            } else {
                imovel.setEsquerdoField("");
            }

            if (imovel.getProprietarios() != null && !imovel.getProprietarios().isEmpty()) {
                imovel.setProprietarioMemorialDescritivo(imovel.getProprietarios().get(0));
            }

            for (Anexo a : imovel.getAnnexCroquis()) {
                InputStream imgInputStream = null;
                if (a != null) {
                    try {

                        if (a.getUrl() != null && a.getNome() != null) {
                            Path path = Paths.get(a.getUrl().concat(a.getNome()));

                            if (path != null) {
                                imgInputStream = new ByteArrayInputStream(Files.readAllBytes(path));
                            }

                        } else {
                            imgInputStream = new ByteArrayInputStream(a.getArquivo());
                        }

                    } catch (IOException ex) {
                        System.err.println(ex);
                        Logger.getLogger(ImovelServico.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

                a.setCroquiRelatorio(imgInputStream);
            }

        }

        URL subreport = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/bci.jasper");
        final String sub = subreport.toString().replace("bci.jasper", "");
        parametros.put("SUBREPORT_DIR", sub);

        RelatorioServico.genReport(parametros, imoveis, Relatorio.MEMORIALDESCRITIVO);

        return true;
    }

    public void reportBillet(byte[] pdfAsBytes) {
        RelatorioServico.genReport(pdfAsBytes);
    }

    public List<Imovel> genMapaImovel() {
        String sql = "SELECT i FROM Imovel i JOIN i.proprietarios p where 1=1 " + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);
        return (List<Imovel>) query.getResultList();
    }

    //DIAGNOSTICO
    public Long diagQtdImovel() {
        String sql = "SELECT count(i) FROM Imovel i where 1=1" + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);
        return (Long) query.getSingleResult();
    }

    public Long diagQtdImovelPorBairro(String bairro) {
        String sql = "SELECT count(i.id) FROM Imovel i JOIN i.enderecoImovel ei "
                + " where lower(ei.bairroDne.nome) like lower(:bairro) " + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("bairro", bairro);

        return (Long) query.getSingleResult();
    }

    public Long diagQtdImovelPendente() {

        List<Imovel> im = new ArrayList<Imovel>();
        String sql = "SELECT count(i.id) FROM Imovel i "
                + "WHERE i.proprietarios is empty "
                + "or i.annex is empty " + this.whereImovelAtivo;
//                + "or i.patrimonio is Null "
//                + "or (i.patrimonio = :p AND (i.rip is Null or i.rip like '') )";

        Query query = getEntityManager().createQuery(sql);
//        query.setParameter("p", Patrimonio.UNIAO);
        return (Long) query.getSingleResult();
    }

    public Long diagFindImoveis(Imovel imovel, Proprietario proprietario, Endereco endereco) {

        String sql = "SELECT count(i.id) FROM Imovel i ";

        if (proprietario != null) {
            if (proprietario.getTipoDocumento() == TipoDocumento.CPF) {
                if ((proprietario.getCpf() != null && !proprietario.getCpf().isEmpty())
                        || (proprietario.getNome() != null && !proprietario.getNome().isEmpty())) {
                    sql += " JOIN i.proprietarios p ";

                }
            }
            if (proprietario.getTipoDocumento() == TipoDocumento.CNPJ) {
                if ((proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty())
                        || (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty())) {
                    sql += " JOIN i.proprietarios p ";

                }
            }
        }

        if (endereco != null) {
            if ((endereco.getCep() != null && !endereco.getCep().isEmpty())
                    || (endereco.getNumero() != null && !endereco.getNumero().isEmpty())
                    || (endereco.getBairro() != null && !endereco.getBairro().isEmpty())
                    || (endereco.getLogradouro() != null && !endereco.getLogradouro().isEmpty())) {
                sql += " JOIN i.enderecoImovel e ";
            }
        }


        sql += " where ";

        if (endereco != null) {
            if (endereco.getCep() != null && !endereco.getCep().isEmpty()) {
                sql += " lower(e.cep) like lower(:cep) and ";
            }
            if (endereco.getNumero() != null && !endereco.getNumero().isEmpty()) {
                sql += " lower(e.numero) like lower(:numero) and ";
            }
            if (endereco.getLogradouro() != null && !endereco.getLogradouro().isEmpty()) {
                sql += " lower(e.logradouro) like lower(:logradouro) and ";
            }
            if (endereco.getBairro() != null && !endereco.getBairro().isEmpty()) {
                sql += " lower(e.bairro) like lower(:bairro) and ";
            }
        }

        if (proprietario != null) {
            if (proprietario.getTipoDocumento() == TipoDocumento.CPF) {
                if (proprietario.getCpf() != null && !proprietario.getCpf().isEmpty()) {
                    sql += " lower(p.cpf) like lower(:cpf) and ";
                }
                if (proprietario.getNome() != null && !proprietario.getNome().isEmpty()) {
                    sql += " lower(p.nome) like lower(:nome) and ";
                }
            }

            if (proprietario.getTipoDocumento() == TipoDocumento.CNPJ) {
                if (proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty()) {
                    sql += " lower(p.cnpj) like lower(:cnpj) and ";
                }
                if (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty()) {
                    sql += " lower(p.nomeFantasia) like lower(:nomeFantasia) and ";
                }
            }
        }

        if (imovel.getInscricaoCadastralD() != null) {
            sql += " i.inscricaoCadastralD = :d and ";
        }
        if (imovel.getInscricaoCadastralS() != null) {
            sql += " i.inscricaoCadastralS = :s and ";
        }
        if (imovel.getInscricaoCadastralQuadra() != null) {
            sql += " i.inscricaoCadastralQuadra = :q and ";
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }
        if (imovel.getInscricaoCadastralUnid() != null) {
            sql += " i.inscricaoCadastralUnid = :u and ";
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }
        if (imovel.getPatrimonio() != null) {
            sql += " i.patrimonio = :patrimonio and ";
        }

        sql += " 1=1 " + this.whereImovelAtivo;

        Query query = getEntityManager().createQuery(sql);
        setParameters(proprietario, query, endereco, imovel, null, null);

        if (imovel.getPatrimonio() != null) {
            query.setParameter("patrimonio", imovel.getPatrimonio());
        }

        return (Long) query.getSingleResult();

    }

    public void relatorioPendencia(List<Imovel> imoveis) {
        HashMap parametros = new HashMap<String, Object>();
        URL rodape = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/rodape_subreport_landscape.jasper");
        parametros.put("RODAPE_SUBREPORT", rodape.toString());
        RelatorioServico.genReport(parametros, imoveis, Relatorio.PENDENCIA);
    }

    public void relatorioRelacaoCadastral(HashMap parametros, Imovel imovel, Proprietario pro, Endereco e) {

        imovel.setProprietarios(new ArrayList<Proprietario>());
        imovel.setEnderecoImovel(e);

        List<Imovel> relacaoImovel = find(imovel, null, null);

        URL subreport = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/relacaocadastro_proprietario.jasper");
        URL rodape = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/rodape_subreport.jasper");
        parametros.put("SUBREPORT_DIR", subreport.toString());
        parametros.put("RODAPE_SUBREPORT", rodape.toString());

        RelatorioServico.genReport(parametros, relacaoImovel, Relatorio.RELACAO_CADASTRAL);
    }

    public void relatorioRelacaoImoveisSimplificado(HashMap parametros, List<Imovel> imoveis) {

        URL subreport = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/relacaoimoveissimplificado_porprietarios.jasper");
        URL rodape = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/rodape_subreport.jasper");
        parametros.put("SUBREPORT_DIR", subreport.toString().replace("relacaoimoveissimplificado_porprietarios.jasper", ""));
        parametros.put("RODAPE_SUBREPORT", rodape.toString());

        RelatorioServico.genReport(parametros, imoveis, Relatorio.RELACAO_IMOVEIS_SIMPLIFICADO);
    }

    public void relatorioPendenciaAreaCessao(HashMap parametros, List<Imovel> imoveis) {

        URL subreport = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/pendenciaareacessao_proprietarios.jasper");
        URL rodape = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/rodape_subreport.jasper");
        URL cabecalho = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/cabecalho_subreport.jasper");

        parametros.put("SUBREPORT_DIR", subreport.toString());
        parametros.put("CABECALHO_SUBREPORT", cabecalho.toString());
        parametros.put("RODAPE_SUBREPORT", rodape.toString());

        parametros.put("titulo", "Pendência - Área da Cessão");
        parametros.put("quantidadeRegistros", imoveis.size());

        parametros.putAll(prefeituraServico.parametroPrefeitura());

        RelatorioServico.genReport(parametros, imoveis, Relatorio.PENDENCIA_AREA_CESSAO);
    }

    public void relatorioGeral(HashMap parametros, List<Imovel> i) {

        parametros.put("quantidade", i.size() + " Registros");

        URL subreport = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/relatoriogeral_subreport.jasper");
        URL rodape = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/rodape_subreport_landscape.jasper");

        parametros.put("SUBREPORT_DIR", subreport.toString());
        parametros.put("RODAPE_SUBREPORT", rodape.toString());

        RelatorioServico.genReport(parametros, i, Relatorio.GERAL);
    }

    public void relatorioPorBairro(HashMap parametros, List<Map<String, Object>> result) {

        URL rodape = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/rodape_subreport.jasper");

        parametros.put("SUBREPORT_DIR", rodape.toString());

        RelatorioServico.genReport(parametros, result, Relatorio.POR_BAIRRO);
    }

    public List<Imovel> pesquisarImoveisPorBairro(Bairro bairro) {
        String sql = "SELECT i FROM Imovel i JOIN i.enderecoImovel ei JOIN ei.bairroDne b ";

        if (bairro != null && bairro.getId() != null) {
            sql += "where b.id = :bairroId " + this.whereImovelAtivo;
        }

        Query query = getEntityManager().createQuery(sql);

        if (bairro != null && bairro.getId() != null) {
            query.setParameter("bairroId", bairro.getId());
        }

        return query.getResultList();
    }

    public List<Imovel> findValidImovel(Imovel imovel, Integer first, Integer pageSize) {
        List<Long> ids = iptuServico.findAllImoveis();
        String select = "SELECT i ";
        String sql = "FROM Imovel i";
        String orderBy = " order by i.id asc";

        Proprietario proprietario = null;

        if (imovel.getProprietarios() != null && !imovel.getProprietarios().isEmpty()) {
            proprietario = imovel.getProprietarios().get(0);
        }

        Endereco endereco = imovel.getEnderecoImovel();

        if (proprietario != null) {
            if (proprietario.getTipoDocumento() == TipoDocumento.CPF) {
                if ((proprietario.getCpf() != null && !proprietario.getCpf().isEmpty())
                        || (proprietario.getNome() != null && !proprietario.getNome().isEmpty())) {
                    sql += " JOIN i.proprietarios p ";
                }
            }
            if (proprietario.getTipoDocumento() == TipoDocumento.CNPJ) {
                if ((proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty())
                        || (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty())) {
                    sql += " JOIN i.proprietarios p ";
                }
            }
        }

        if (endereco != null) {
            if ((endereco.getCep() != null && !endereco.getCep().isEmpty())
                    || (endereco.getNumero() != null && !endereco.getNumero().isEmpty())
                    || (endereco.getBairro() != null && !endereco.getBairro().isEmpty())
                    || (endereco.getLogradouro() != null && !endereco.getLogradouro().isEmpty())) {
                sql += " JOIN i.enderecoImovel e ";
            }
        }

        sql += " where ";

        if (endereco != null) {
            if (endereco.getCep() != null && !endereco.getCep().isEmpty()) {
                sql += " lower(e.cep) like lower(:cep) and ";
            }
            if (endereco.getNumero() != null && !endereco.getNumero().isEmpty()) {
                sql += " lower(e.numero) like lower(:numero) and ";
            }
            if (endereco.getLogradouro() != null && !endereco.getLogradouro().isEmpty()) {
                sql += " lower(e.logimovelcroquiradouro) like lower(:logradouro) and ";
            }
            if (endereco.getBairro() != null && !endereco.getBairro().isEmpty()) {
                sql += " lower(e.bairro) like lower(:bairro) and ";
            }
        }

        if (proprietario != null) {
            if (proprietario.getTipoDocumento() == TipoDocumento.CPF) {
                if (proprietario.getCpf() != null && !proprietario.getCpf().isEmpty()) {
                    sql += " lower(p.cpf) like lower(:cpf) and ";
                }
                if (proprietario.getNome() != null && !proprietario.getNome().isEmpty()) {
                    sql += " lower(p.nome) like lower(:nome) and ";
                }
            }

            if (proprietario.getTipoDocumento() == TipoDocumento.CNPJ) {
                if (proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty()) {
                    sql += " lower(p.cnpj) like lower(:cnpj) and ";
                }
                if (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty()) {
                    sql += " lower(p.nomeFantasia) like lower(:nomeFantasia) and ";
                }
            }

            if (proprietario.getMinhaCasaMinhaVida() != null && proprietario.getMinhaCasaMinhaVida()) {
                sql += " p.minhaCasaimovelcroquiMinhaVida = true AND ";
            }

            if (proprietario.getBolsaFamilia() != null && proprietario.getBolsaFamilia()) {
                sql += " p.bolsaFamilia = true AND ";
            }
        }

        if (imovel.getInscricaoCadastralD() != null) {
            sql += " i.inscricaoCadastralD = :d and ";
        }
        if (imovel.getInscricaoCadastralS() != null) {
            sql += " i.inscricaoCadastralS = :s and ";
        }
        if (imovel.getInscricaoCadastralQuadra() != null) {
            sql += " i.inscricaoCadastralQuadra = :q and ";
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }
        if (imovel.getInscricaoCadastralUnid() != null) {
            sql += " i.inscricaoCadastralUnid = :u and ";
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }

        if (ids != null && !ids.isEmpty()) {
            sql += " i.id in :ids and ";
        }

        sql += " 1=1 " + this.whereImovelAtivo;

        Query query = getEntityManager().createQuery(select.concat(sql).concat(orderBy));

        if (ids != null && !ids.isEmpty()) {
            query.setParameter("ids", ids);
        }
        setParameters(proprietario, query, endereco, imovel, ids, null);

        setQuantidadeRegistros(sql, query, proprietario, endereco, imovel, ids, null);

        if (first != null && pageSize != null) {
            query.setFirstResult(first).setMaxResults(pageSize);
        }

        return query.getResultList();
    }

    @Override
    public List<Imovel> find(Imovel imovel, Integer first, Integer pageSize) {
        String select = "SELECT distinct i ";
        String sql = "FROM Imovel i ";
        String orderBy = " order by i.id asc";

        Proprietario proprietario = null;

        if (imovel.getProprietarios() != null && !imovel.getProprietarios().isEmpty()) {
            proprietario = imovel.getProprietarios().get(0);
        }

        Endereco endereco = imovel.getEnderecoImovel();

        if (this.imovelComProprietario != null && this.imovelComProprietario) {
            sql += " JOIN i.proprietarios p ";
        } else if (proprietario != null) {
//            if (proprietario.getTipoDocumento() == null || proprietario.getTipoDocumento() == TipoDocumento.CPF) {
//                if ((proprietario.getCpf() != null && !proprietario.getCpf().isEmpty())
//                        || (proprietario.getNome() != null && !proprietario.getNome().isEmpty())
//                        || proprietario.getRendaFamiliar() != null) {
            sql += " JOIN i.proprietarios p ";
//                }
//            } else if (proprietario.getTipoDocumento() == TipoDocumento.CNPJ) {
//                if ((proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty())
//                        || (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty())) {
//                    sql += " JOIN i.proprietarios p ";
//                }
//            }
        }

        if (endereco != null || (this.imovelComNumero != null && this.imovelComNumero)) {
            if ((endereco.getCep() != null && !endereco.getCep().isEmpty())
                    || (endereco.getNumero() != null && !endereco.getNumero().isEmpty())
                    || (endereco.getBairro() != null && !endereco.getBairro().isEmpty())
                    || (endereco.getLogradouro() != null && !endereco.getLogradouro().isEmpty())
                    || (this.imovelComNumero != null) || (this.bairros != null && !this.bairros.isEmpty())) {

                sql += " JOIN i.enderecoImovel e ";
            }
        }

        if (this.imovelComDimensao != null) {
            sql += " JOIN i.dimensoes di ";
        }

        if (this.imovelComCoordenadaConfrontacao != null) {
            if (this.imovelComCoordenadaConfrontacao) {
                sql += " JOIN i.coordenadasDimensoes cd ";
            }
        }

        sql += " where ";

        if (imovel.getId() != null) {
            sql += " i.id = " + imovel.getId() + " and ";
        }

        if (endereco != null || (this.imovelComNumero != null && this.imovelComNumero)) {
            if (endereco.getCep() != null && !endereco.getCep().isEmpty()) {
                sql += " lower(e.cep) like lower(:cep) and ";
            }

            if (this.imovelComNumero != null && !this.imovelComNumero) {
                sql += " (e.numero is null or e.numero like '') AND ";
            }
            if ((this.imovelComNumero != null && this.imovelComNumero)
                    && (endereco.getNumero() == null || endereco.getNumero().isEmpty())) {

                sql += " (e.numero is not null or e.numero not like '') AND ";

            } else if (endereco.getNumero() != null && !endereco.getNumero().isEmpty()) {
                sql += " lower(e.numero) like lower(:numero) and ";
            }

            if (endereco.getLogradouro() != null && !endereco.getLogradouro().isEmpty()) {
                sql += " lower(e.logradouro) like lower(:logradouro) and ";
            }
            if (endereco.getBairro() != null && !endereco.getBairro().isEmpty()) {
                sql += " (lower(e.bairro) like lower(:bairro) or lower(e.bairroDne.nome) like lower(:bairro)) and ";
            }
        }

        if (this.bairros != null && !this.bairros.isEmpty()) {
            bairrosId = new ArrayList<Long>();

            for (Bairro bairro : this.bairros) {
                bairrosId.add(bairro.getId());
            }

            sql += " e.bairroDne.id in :bairrosId AND ";
            orderBy = " order by e.bairroDne.nome ASC, i.id ASC ";
        }

        if (this.imovelComProprietario != null && !this.imovelComProprietario) {
            sql += " (i.proprietarios IS EMPTY) AND ";
        } else {
            if (proprietario != null) {
                if (proprietario.getTipoDocumento() == TipoDocumento.CPF) {
                    if (proprietario.getCpf() != null && !proprietario.getCpf().isEmpty()) {
                        sql += " lower(p.cpf) like lower(:cpf) and ";
                    }
                    if (proprietario.getNome() != null && !proprietario.getNome().isEmpty()) {
                        sql += " lower(p.nome) like lower(:nome) and ";
                    }
                }

                if (proprietario.getTipoDocumento() == TipoDocumento.CNPJ) {
                    if (proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty()) {
                        sql += " lower(p.cnpj) like lower(:cnpj) and ";
                    }
                    if (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty()) {
                        sql += " lower(p.nomeFantasia) like lower(:nomeFantasia) and ";
                    }
                }

                if (proprietario.getTempoMoradia() != null && !proprietario.getTempoMoradia().trim().isEmpty()) {
                    sql += " (lower(p.tempoMoradia) like lower(:tempoMoradia) AND p.tempoMoradia is not null and p.tempoMoradia not like '') AND ";
                }
                if (proprietario.getTempoMoradiaMunicipio() != null && !proprietario.getTempoMoradiaMunicipio().trim().isEmpty()) {
                    sql += " (lower(p.tempoMoradiaMunicipio) like lower(:tempoMoradiaMunicipio) AND p.tempoMoradiaMunicipio is not null and p.tempoMoradiaMunicipio not like '') AND ";
                }

                if (proprietario.getRendaFamiliar() != null) {
                    sql += " (p.rendaFamiliar like :rendaFamiliar AND p.rendaFamiliar is not null and p.rendaFamiliar not like '') AND ";
                }
                if (proprietario.getComposicaoFamiliar() != null) {
                    sql += " lower(p.composicaoFamiliar) like lower(:composicaoFamiliar) AND p.composicaoFamiliar is not null AND ";
                }
                if (proprietario.getRendaFamiliar() != null) {
                    sql += " lower(p.rendaFamiliar) like lower(:rendaFamiliar) AND p.rendaFamiliar is not null AND ";
                }
            }
        }

        if (imovel.getInscricaoCadastralD() != null) {
            sql += " i.inscricaoCadastralD = :d and ";
        }
        if (imovel.getInscricaoCadastralS() != null) {
            sql += " i.inscricaoCadastralS = :s and ";
        }

        if (this.imovelQuadras != null && !this.imovelQuadras.isEmpty()) {
            sql += " i.inscricaoCadastralQuadra in (" + this.imovelQuadras.toString().replace("[", "").replace("]", "") + ") and ";

        } else if (imovel.getInscricaoCadastralQuadra() != null) {
            sql += " i.inscricaoCadastralQuadra = :q and ";
        }

        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }
        if (imovel.getInscricaoCadastralUnid() != null) {
            sql += " i.inscricaoCadastralUnid = :u and ";
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }

        if (imovel.getComando() != null) {
            sql += " i.comando like :comando and ";
        }

        if (imovel.getRip() != null && !imovel.getRip().isEmpty()) {
            sql += " i.rip like :rip AND ";
        }

        if (imovel.getUsoImovel() != null) {
            sql += " i.usoImovel like :usoImovel AND ";
        }

        if (imovel.getTipoDocumentoImovel() != null) {
            sql += " i.tipoDocumentoImovel like :tipoDocumentoImovel AND ";
        }

        List<Long> idsComCroqui = null;

        if (this.imovelComCroqui != null) {
            idsComCroqui = getEntityManager().createQuery("select distinct a.imovelCroqui.id from Anexo a where a.ativo = true").getResultList();
            if (this.imovelComCroqui) {
                sql += "i.id in :idsComCroqui and  ";
            } else {

                sql += "i.id not in :idsComCroqui and ";
            }
        }

        if (this.imovelComAnexo != null) {

            List<Long> idsComAnexo = getEntityManager().createQuery("select distinct a.imovel.id from Anexo a where a.ativo = true").getResultList();

            if (this.imovelComAnexo) {
                sql += "i.id in (" + idsComAnexo.toString().replace("[", "").replace("]", "") + ") AND ";
            } else {
                sql += "i.id not in (" + idsComAnexo.toString().replace("[", "").replace("]", "") + ") AND ";
            }
        }

        if (this.imovelComCoordenadaConfrontacao != null) {
            if (!this.imovelComCoordenadaConfrontacao) {
                sql += " i.coordenadasDimensoes is empty and ";
            }
        }

        if (this.imovelComDimensao != null) {
            if (this.imovelComDimensao) {
                sql += " di.areaTerreno is not null AND "
                        + "di.areaUnidade is not null AND "
                        + "di.areaTotalEdificacao is not null AND "
                        + "di.numPavimentacaoEdific is not null AND "
                        + "di.testadaImovel is not null AND "
                        + "di.testadaServidaConservCalcamento is not null AND "
                        + "di.testadaServidaPorIluminacaoPublica is not null AND "
                        + "di.testadaServidaLimpezaPublica is not null AND "
                        + "di.perimetro is not null AND ";

            } else if (!this.imovelComDimensao) {
                sql += " (i.dimensoes is null OR "
                        + " (di.areaTerreno is null AND "
                        + "di.areaUnidade is null AND "
                        + "di.areaTotalEdificacao is null AND "
                        + "di.numPavimentacaoEdific is null AND "
                        + "di.testadaImovel is null AND "
                        + "di.testadaServidaConservCalcamento is null AND "
                        + "di.testadaServidaPorIluminacaoPublica is null AND "
                        + "di.testadaServidaLimpezaPublica is null AND "
                        + "di.perimetro is null)) AND ";
            }
        }
        if (this.imovelComConfrontacao != null) {

            if (this.imovelComConfrontacao) {
                sql += "((i.frente IS NOT NULL OR i.frente NOT LIKE '') AND "
                        + "(i.frenteRua IS NOT NULL OR i.frenteRua NOT LIKE '') AND "
                        + "i.frenteMedindo IS NOT NULL AND "
                        + "(i.fundo IS NOT NULL OR i.fundo NOT LIKE '') AND "
                        + "(i.fundoRua IS NOT NULL OR i.fundoRua NOT LIKE '') AND "
                        + "i.fundoMedindo IS NOT NULL AND "
                        + "(i.ladoEsquerdo IS NOT NULL OR i.ladoEsquerdo LIKE '') AND  "
                        + "(i.ladoEsquerdoRua IS NOT NULL OR i.ladoEsquerdoRua NOT LIKE '') AND "
                        + "i.ladoEsquerdoMedindo IS NOT NULL AND "
                        + "(i.ladoDireito IS NOT NULL OR i.ladoDireito NOT LIKE '') AND "
                        + "(i.ladoDireitoRua IS NOT NULL OR i.ladoDireitoRua NOT LIKE '') AND "
                        + "i.ladoDireitoMedindo IS NOT NULL) AND ";
            } else {
                sql += "((i.frente is null OR i.frente like '') AND "
                        + "(i.frenteRua is null OR i.frenteRua like '') AND "
                        + "i.frenteMedindo is null AND "
                        + "(i.fundo is null OR i.fundo like '') AND "
                        + "(i.fundoRua is null OR i.fundoRua like '') AND "
                        + "i.fundoMedindo is null AND "
                        + "(i.ladoEsquerdo is null OR i.ladoEsquerdo like '') AND  "
                        + "(i.ladoEsquerdoRua is null OR i.ladoEsquerdoRua like '') AND "
                        + "i.ladoEsquerdoMedindo is null AND "
                        + "(i.ladoDireito is null OR i.ladoDireito like '') AND "
                        + "(i.ladoDireitoRua is null OR i.ladoDireitoRua like '') AND "
                        + "i.ladoDireitoMedindo is null) AND ";
            }
        }

        if (imovel.getSituacaoImovel() != null && !imovel.getSituacaoImovel().equals(SituacaoImovel.EM_BRANCO)) {
            sql += " i.situacaoImovel like '" + imovel.getSituacaoImovel().name() + "' AND ";
        } else if (imovel.getSituacaoImovel() != null && imovel.getSituacaoImovel().equals(SituacaoImovel.EM_BRANCO)) {
            sql += " (i.situacaoImovel like '' OR i.situacaoImovel is null) AND ";
        }

        if (imovel.getCaracterizacao() != null && !imovel.getCaracterizacao().equals(Caracterizacao.EM_BRANCO)) {
            sql += " i.caracteridistinctzacao like '" + imovel.getCaracterizacao().name() + "' AND ";
        } else if (imovel.getCaracterizacao() != null && imovel.getCaracterizacao().equals(Caracterizacao.EM_BRANCO)) {
            sql += " (i.caracterizacao like '' or i.caracterizacao is null) AND ";
        }

        if (imovel.getUsoImovel() != null && !imovel.getUsoImovel().equals(UsoImovel.EM_BRANCO)) {
            sql += " i.usoImovel like '" + imovel.getUsoImovel().name() + "' AND ";
        } else if (imovel.getUsoImovel() != null && !imovel.getUsoImovel().equals(UsoImovel.EM_BRANCO)) {
            sql += " i.usoImovel like '" + imovel.getUsoImovel().name() + "' AND ";
        }

        sql += " 1=1 " + this.whereImovelAtivo;

        System.err.println("sql = " + sql);

        if (this.orderBy != null && !this.orderBy.isEmpty()) {
            orderBy = " order by i." + this.orderBy + " asc";
        }

        Query query = getEntityManager().createQuery(select.concat(sql).concat(orderBy));

        setQuantidadeRegistros(sql, query, proprietario, endereco, imovel, null, idsComCroqui);

        if (this.imovelComCroqui != null) {
            setParameters(proprietario, query, endereco, imovel, null, idsComCroqui);
        } else {
            setParameters(proprietario, query, endereco, imovel, null, null);
        }

        if (first != null && pageSize != null) {
            query.setFirstResult(first).setMaxResults(pageSize);
        }

        return query.getResultList();
    }

    @Transient
    private void setParameters(Proprietario proprietario, Query query, Endereco endereco, Imovel imovel, List<Long> ids, List<Long> idsComCroqui) {
        if (this.imovelComProprietario == null || this.imovelComProprietario) {
            if (proprietario != null) {
                if (proprietario.getTipoDocumento() == TipoDocumento.CPF) {
                    if (proprietario.getCpf() != null && !proprietario.getCpf().isEmpty()) {
                        query.setParameter("cpf", proprietario.getCpf());
                    }
                    if (proprietario.getNome() != null && !proprietario.getNome().isEmpty()) {
                        query.setParameter("nome", "%" + proprietario.getNome().toLowerCase().replaceAll(" ", "%") + "%");
                    }
                }
                if (proprietario.getTipoDocumento() == TipoDocumento.CNPJ) {
                    if (proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty()) {
                        query.setParameter("cnpj", proprietario.getCnpj());
                    }
                    if (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty()) {
                        query.setParameter("nomeFantasia", "%" + proprietario.getNomeFantasia().toLowerCase().replaceAll(" ", "%") + "%");
                    }
                }

                if (proprietario.getTempoMoradia() != null && !proprietario.getTempoMoradia().trim().isEmpty()) {
                    query.setParameter("tempoMoradia", "%" + proprietario.getTempoMoradia().trim().toLowerCase().replace(" ", "%") + "%");
                }
                if (proprietario.getTempoMoradiaMunicipio() != null && !proprietario.getTempoMoradiaMunicipio().trim().isEmpty()) {
                    query.setParameter("tempoMoradiaMunicipio", "%" + proprietario.getTempoMoradiaMunicipio().trim().toLowerCase().replace(" ", "%") + "%");
                }

                if (proprietario.getRendaFamiliar() != null) {
                    query.setParameter("rendaFamiliar", proprietario.getRendaFamiliar().name());
                }
                if (proprietario.getComposicaoFamiliar() != null) {
                    query.setParameter("composicaoFamiliar", "%" + proprietario.getComposicaoFamiliar().name() + "%");
                }
                if (proprietario.getRendaFamiliar() != null) {
                    query.setParameter("rendaFamiliar", "%" + proprietario.getRendaFamiliar().name() + "%");
                }
            }
        }
        if (endereco != null) {
            if (endereco.getCep() != null && !endereco.getCep().isEmpty()) {
                query.setParameter("cep", endereco.getCep());
            }

            if ((this.imovelComNumero == null || this.imovelComNumero)
                    && (endereco.getNumero() != null && !endereco.getNumero().isEmpty())) {
                query.setParameter("numero", "%" + endereco.getNumero() + "%");
            }

            if (endereco.getLogradouro() != null && !endereco.getLogradouro().isEmpty()) {
                query.setParameter("logradouro", "%" + endereco.getLogradouro().toLowerCase().replaceAll(" ", "%") + "%");
            }

            if (endereco.getBairro() != null && !endereco.getBairro().isEmpty()) {
                query.setParameter("bairro", "%" + endereco.getBairro().toLowerCase().replaceAll(" ", "%") + "%");
            }
        }

        if (imovel.getInscricaoCadastralD() != null) {
            query.setParameter("d", imovel.getInscricaoCadastralD());
        }

        if (imovel.getInscricaoCadastralS() != null) {
            query.setParameter("s", imovel.getInscricaoCadastralS());
        }

        if ((this.imovelQuadras == null || this.imovelQuadras.isEmpty()) && (imovel.getInscricaoCadastralQuadra() != null)) {
            query.setParameter("q", imovel.getInscricaoCadastralQuadra());
        }

        if (imovel.getInscricaoCadastralUnid() != null) {
            query.setParameter("u", imovel.getInscricaoCadastralUnid());
        }

        if (imovel.getInscricaoCadastralLote() != null) {
            query.setParameter("l", imovel.getInscricaoCadastralLote());
        }

        if (imovel.getUsoImovel() != null) {
            query.setParameter("usoImovel", "%" + imovel.getUsoImovel().name() + "%");
        }

        if (imovel.getComando() != null) {
            query.setParameter("comando", "%" + imovel.getComando().name() + "%");
        }

        if (imovel.getRip() != null && !imovel.getRip().isEmpty()) {
            query.setParameter("rip", "%" + imovel.getRip() + "%");
        }

        if (imovel.getTipoDocumentoImovel() != null) {
            query.setParameter("tipoDocumentoImovel", "%" + imovel.getTipoDocumentoImovel().name() + "%");
        }

        if (this.bairros != null && !this.bairros.isEmpty()) {
            query.setParameter("bairrosId", this.bairrosId);
        }

        if (ids != null && !ids.isEmpty()) {
            query.setParameter("ids", ids);
        }

        if (idsComCroqui != null && !idsComCroqui.isEmpty()) {
            query.setParameter("idsComCroqui", idsComCroqui);
        }
    }

    private void setQuantidadeRegistros(String sql, Query query, Proprietario proprietario, Endereco endereco, Imovel imovel, List<Long> ids, List<Long> idsComCroqui) {

        String select = "SELECT count(distinct i) ";

        query = getEntityManager().createQuery(select + sql);

        setParameters(proprietario, query, endereco, imovel, ids, idsComCroqui);

        quantidadeRegistrosResults = (Long) query.getSingleResult();
    }

    @Override
    public Long quantidadeRegistros() {
        return quantidadeRegistrosResults;
    }

    public Imovel existImovelContribuinte(Proprietario pro, Imovel imovel) {

        String sql = "Select i from Imovel i JOIN i.proprietarios p WHERE ";

        if (pro.getTipoDocumento() == TipoDocumento.CPF) {
            sql += " lower(p.cpf) like lower(:cpf) and";
        } else {
            sql += " lower(p.cnpj) like lower(:cnpj) and ";
        }

        if (imovel.getInscricaoCadastralD() != null) {
            sql += " i.inscricaoCadastralD = :d and ";
        }
        if (imovel.getInscricaoCadastralS() != null) {
            sql += " i.inscricaoCadastralS = :s and ";
        }
        if (imovel.getInscricaoCadastralQuadra() != null) {
            sql += " i.inscricaoCadastralQuadra = :q and ";
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }
        if (imovel.getInscricaoCadastralUnid() != null) {
            sql += " i.inscricaoCadastralUnid = :u and ";
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }

        sql += " 1=1 " + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);
        if (pro.getTipoDocumento() == TipoDocumento.CPF) {
            query.setParameter("cpf", pro.getCpf());
        } else {
            query.setParameter("cnpj", pro.getCnpj());
        }

        if (imovel.getInscricaoCadastralD() != null) {
            query.setParameter("d", imovel.getInscricaoCadastralD());
        }

        if (imovel.getInscricaoCadastralS() != null) {
            query.setParameter("s", imovel.getInscricaoCadastralS());
        }

        if (imovel.getInscricaoCadastralQuadra() != null) {
            query.setParameter("q", imovel.getInscricaoCadastralQuadra());
        }

        if (imovel.getInscricaoCadastralUnid() != null) {
            query.setParameter("u", imovel.getInscricaoCadastralUnid());
        }
        if (imovel.getInscricaoCadastralLote() != null) {
            query.setParameter("l", imovel.getInscricaoCadastralLote());
        }

        if (imovel.getPatrimonio() != null) {
            query.setParameter("patrimonio", imovel.getPatrimonio());
        }

        try {
            imovel = (Imovel) query.getResultList().get(0);

        } catch (NoResultException nr) {
            return null;
        } catch (NonUniqueResultException nre) {
            return null;
        } catch (Exception e) {
            return null;
        }
        return imovel;
    }

    public Imovel existeImovelContribuinte(String D, String S, String Q, String L, String U, Usuario usuario) {

        Imovel imovel;
        String sql = "Select i from Imovel i JOIN i.proprietarios p WHERE ";

        if (usuario.getSenha().length() == 11) {
            sql += " lower(p.cpf) like lower(" + usuario.getSenha() + ") and";
        } else if (usuario.getSenha().length() == 14) {
            sql += " lower(p.cnpj) like lower(" + usuario.getSenha() + ") and ";
        }
        if (D != null) {
            sql += " i.inscricaoCadastralD = :d and ";
        }
        if (S != null) {
            sql += " i.inscricaoCadastralS = :s and ";
        }
        if (Q != null) {
            sql += " i.inscricaoCadastralQuadra = :q and ";
        }
        if (L != null) {
            sql += " i.inscricaoCadastralLote = :l and ";
        }
        if (U != null) {
            sql += " i.inscricaoCadastralUnid = :u and ";
        }

        sql += " 1=1 " + this.whereImovelAtivo;
        Query query = getEntityManager().createQuery(sql);

        if (D != null) {
            query.setParameter("d", Integer.parseInt(D));
        }

        if (S != null) {
            query.setParameter("s", Integer.parseInt(S));
        }

        if (Q != null) {
            query.setParameter("q", Integer.parseInt(Q));
        }

        if (U != null) {
            query.setParameter("u", Integer.parseInt(U));
        }
        if (L != null) {
            query.setParameter("l", Integer.parseInt(L));
        }

        try {
            imovel = (Imovel) query.getResultList().get(0);

        } catch (NoResultException nr) {
            return null;
        } catch (NonUniqueResultException nre) {
            return null;
        } catch (Exception e) {
            return null;
        }
        return imovel;
    }

    public String getInscricaoCadastral(Imovel imovel) {
        return getInscricaoCadastral(imovel.getInscricaoCadastralD(), imovel.getInscricaoCadastralS(), imovel.getInscricaoCadastralQuadra(), imovel.getInscricaoCadastralLote(), imovel.getInscricaoCadastralUnid());
    }

    public String getInscricaoCadastralFormatada(Imovel imovel) {

        String inscricao = getInscricaoCadastral(imovel.getInscricaoCadastralD(), imovel.getInscricaoCadastralS(), imovel.getInscricaoCadastralQuadra(), imovel.getInscricaoCadastralLote(), imovel.getInscricaoCadastralUnid()).replace(",", "");

        inscricao = inscricao.substring(0, 2) + "." + inscricao.substring(2, 4) + "." + inscricao.substring(4, 7) + "." + inscricao.substring(7, 11) + "." + inscricao.substring(11, inscricao.length());

        return inscricao;
    }

    public String getInscricaoCadastral(Integer distrito, Integer setor, Integer quadra, Integer lote, Integer unidade) {
        DecimalFormat d = new DecimalFormat("");
        d.setMinimumIntegerDigits(2);
        String inscricaoCadastral = "";

        inscricaoCadastral += d.format(distrito == null ? 0 : distrito);
        inscricaoCadastral += d.format(setor == null ? 0 : setor);
        d.setMinimumIntegerDigits(3);
        inscricaoCadastral += d.format(quadra == null ? 0 : quadra);
        d.setMinimumIntegerDigits(4);
        d.setDecimalSeparatorAlwaysShown(false);
        inscricaoCadastral += d.format(lote == null ? 0 : lote);
        d.setMinimumIntegerDigits(2);
        inscricaoCadastral += d.format(unidade == null ? 0 : unidade);

        return inscricaoCadastral;
    }

    public String confrontanteLadoEsquerdo(Imovel imovel) {

        String confrontante = "", sql = "SELECT i FROM " + Imovel.class.getSimpleName() + " i "
                + "WHERE i.inscricaoCadastralLote < :inscricaoCadastralLote "
                + "AND i.inscricaoCadastralQuadra = :inscricaoCadastralQuadra "
                + "AND i.inscricaoCadastralS = :inscricaoCadastralS ";

        Query query = getEntityManager().createQuery(sql).setMaxResults(1);
        query.setParameter("inscricaoCadastralLote", imovel.getInscricaoCadastralLote());
        query.setParameter("inscricaoCadastralQuadra", imovel.getInscricaoCadastralQuadra());
        query.setParameter("inscricaoCadastralS", imovel.getInscricaoCadastralS());

        Imovel result = null;
        try {
            result = (Imovel) query.getSingleResult();
        } catch (NoResultException nre) {
            result = null;
        } catch (Exception e) {
            System.err.println(e);
        }

        if (result != null && result.getProprietarios() != null && !result.getProprietarios().isEmpty()) {
            confrontante = " o imóvel do(a) ";
            confrontante += proprietarioServico.getNomeProprietarios(result.getProprietarios());
        }

        return confrontante;
    }

    public String confrontanteLadoDireito(Imovel imovel) {

        String confrontante = "", sql = "SELECT i FROM " + Imovel.class.getSimpleName() + " i "
                + "WHERE i.inscricaoCadastralLote > :inscricaoCadastralLote "
                + "AND i.inscricaoCadastralQuadra = :inscricaoCadastralQuadra "
                + "AND i.inscricaoCadastralS = :inscricaoCadastralS ";

        Query query = getEntityManager().createQuery(sql).setMaxResults(1);
        query.setParameter("inscricaoCadastralLote", imovel.getInscricaoCadastralLote());
        query.setParameter("inscricaoCadastralQuadra", imovel.getInscricaoCadastralQuadra());
        query.setParameter("inscricaoCadastralS", imovel.getInscricaoCadastralS());

        Imovel result = null;
        try {
            result = (Imovel) query.getSingleResult();
        } catch (Exception e) {
            System.err.println("Sem confrontante, lado direito !");
        }
        if (result != null && result.getProprietarios() != null && !result.getProprietarios().isEmpty()) {
            confrontante = " o imóvel do(a) "
                    + proprietarioServico.getNomeProprietarios(result.getProprietarios());
        }

        return confrontante;
    }

    public List<Object[]> migrarDadosParaProprietario() {

        String sql = "select distinct ip.proprietarios_id, i.tempomoradia, i.tempomoradiamunicipio, i.bolsafamilia, "
                + "          i.valorbolsafamilia, i.minhacasaminhavida, i.composicaofamiliar, i.rendafamiliar "
                + "from imovel i "
                + "join imovel_proprietario ip on ip.imovel_id = i.id "
                + "where i.bolsafamilia is not null "
                + "group by i.id,ip.proprietarios_id "
                + "order by ip.proprietarios_id ";

        Query query = getEntityManager().createNativeQuery(sql);

        return query.getResultList();

    }

    public Boolean getImovelComNumero() {
        return imovelComNumero;
    }

    public void setImovelComNumero(Boolean imovelComNumero) {
        this.imovelComNumero = imovelComNumero;
    }

    public Boolean getImovelComCroqui() {
        return imovelComCroqui;
    }

    public void setImovelComCroqui(Boolean imovelComCroqui) {
        this.imovelComCroqui = imovelComCroqui;
    }

    public Boolean getImovelComAnexo() {
        return imovelComAnexo;
    }

    public void setImovelComAnexo(Boolean imovelComAnexo) {
        this.imovelComAnexo = imovelComAnexo;
    }

    public Boolean getImovelIsentoIPTU() {
        return imovelIsentoIPTU;
    }

    public void setImovelIsentoIPTU(Boolean imovelIsentoIPTU) {
        this.imovelIsentoIPTU = imovelIsentoIPTU;
    }

    public Boolean getImovelIsentoSTU() {
        return imovelIsentoSTU;
    }

    public void setImovelIsentoSTU(Boolean imovelIsentoSTU) {
        this.imovelIsentoSTU = imovelIsentoSTU;
    }

    public List<Bairro> getBairros() {
        return bairros;
    }

    public void setBairros(List<Bairro> bairros) {
        this.bairros = bairros;
    }

    public Boolean getImovelComProprietario() {
        return imovelComProprietario;
    }

    public void setImovelComProprietario(Boolean imovelComProprietario) {
        this.imovelComProprietario = imovelComProprietario;
    }

    public Boolean getImovelComDimensao() {
        return imovelComDimensao;
    }

    public void setImovelComDimensao(Boolean imovelComDimensao) {
        this.imovelComDimensao = imovelComDimensao;
    }

    public Boolean getImovelComConfrontacao() {
        return imovelComConfrontacao;
    }

    public void setImovelComConfrontacao(Boolean imovelComConfrontacao) {
        this.imovelComConfrontacao = imovelComConfrontacao;
    }

    public Boolean getImovelComCoordenadaConfrontacao() {
        return imovelComCoordenadaConfrontacao;
    }

    public void setImovelComCoordenadaConfrontacao(Boolean imovelComCoordenadaConfrontacao) {
        this.imovelComCoordenadaConfrontacao = imovelComCoordenadaConfrontacao;
    }

    /**
     * Relatório STS iptu 2015
     *
     * @param grupo
     * @param bairro
     * @param proprietario
     * @param documentos
     * @return
     */
    public List<Imovel> relatorioSts(String sql) {

        Query query = getEntityManager().createQuery(sql);

        System.err.println(query.getResultList().size());
        return query.getResultList();
    }

    /**
     * Pesquisa o Imóvel com id maior que o id informado.
     *
     * @param id do imóvel
     */
    public Long pesquisarProximoImovel(Long id) {
        String sql = "select i.id from " + Imovel.class.getSimpleName() + " i "
                + "where i.id > " + id
                + " order by i.id asc ";

        Query query = getEntityManager().createQuery(sql).setMaxResults(1);

        try {

            return (Long) query.getSingleResult();

        } catch (NoResultException e) {
            return null;
        }
    }

    /**
     * Pesquisa o Imóvel com id menor que o id informado.
     *
     * @param id do imóvel
     */
    public Long pesquisarImovelAnterior(Long id) {
        String sql = "select i.id from " + Imovel.class.getSimpleName() + " i "
                + "where i.id < " + id
                + " order by i.id desc ";

        try {
            Query query = getEntityManager().createQuery(sql).setMaxResults(1);

            return (Long) query.getSingleResult();

        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Object[]> pesquisarRelatorioSetorBairro(Integer setor, List<Quadra> quadras) {

        String quadrasNumero = "";

        if (quadras != null && !quadras.isEmpty()) {

            quadrasNumero = " and i.inscricaoCadastralQuadra in (";

            for (int i = 0; i < quadras.size(); i++) {

                quadrasNumero += quadras.get(i).getNumero();

                if (i < quadras.size() - 1) {
                    quadrasNumero += ", ";
                }
            }

            quadrasNumero += ")";
        }


        String sql = "select i.inscricaoCadastralS setor, i.inscricaoCadastralQuadra quadra, count(i) quantidade "
                + "from " + Imovel.class.getSimpleName() + " i "
                + "where i.inscricaoCadastralS = " + setor + quadrasNumero
                + " and i.ativo = true "
                + "group by i.inscricaoCadastralS, i.inscricaoCadastralQuadra "
                + "order by i.inscricaoCadastralQuadra";

        Query query = getEntityManager().createQuery(sql);

        return query.getResultList();
    }

    public void relatorioPorSetorQuadra(HashMap parametros, List<Map<String, Object>> result) {
        URL rodape = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/rodape_subreport.jasper");
        URL cabecalho = Thread.currentThread().getContextClassLoader().getResource("br/com/foxinline/relatorio/cabecalho_subreport.jasper");

        parametros.put("SUBREPORT_DIR", rodape.toString());
        parametros.put("CABECALHO_DIR", cabecalho.toString());

        RelatorioServico.genReport(parametros, result, Relatorio.POR_SETOR_QUADRA);
    }

    public void setImovelQuadras(List<Integer> imovelQuadras) {
        this.imovelQuadras = imovelQuadras;
    }

    public String getOrderBy() {
        return orderBy;
    }

    public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
    }

    private void descricaoPerimetro(Imovel imovel, Extenso extensoInteiro, String extensoDecimalString) {
        int num = 0;
        int tam = imovel.getCoordenadasDimensoes().size();
        String texto_perimetro = "           Partindo do vértice ";

        for (Coordenada c : imovel.getCoordenadasDimensoes()) {
            if (c == imovel.getCoordenadasDimensoes().get(0)) {
                texto_perimetro += c.getPonto() != null ? c.getPonto() : "";
            }

            texto_perimetro += " com coordenadas UTM N = " + c.getConvN() + " e E = " + c.getConvE();

            if (c.getAzimute() != null && !c.getAzimute().isEmpty()) {
                texto_perimetro += " e com azimute de " + c.getAzimute() + " e ";

            }

            if (c.getDistancia() != null && !c.getDistancia().isEmpty()) {
                texto_perimetro += " e distância de " + c.getDistancia();

                if (c.getLimite() != null && !c.getLimite().isEmpty()) {
                    texto_perimetro += " " + c.getLimite();
                }
            }

            if (c != imovel.getCoordenadasDimensoes().get(tam - 1)) {
                texto_perimetro += ", deste ponto segue";
            }

        }

        Extenso extensoPerimetro = new Extenso(new BigDecimal(imovel.getPerimeField().trim().replace("m", "").split(",")[0]));
        Extenso extensoPerimetroDecimal = new Extenso(new BigDecimal(imovel.getPerimeField().trim().replace("m", "").split(",")[1]));

        String centimetros = "";
        if (extensoPerimetroDecimal != null) {
            centimetros = "e " + extensoPerimetroDecimal.toString() + " centímetros";
        }

        texto_perimetro += "; perfazendo assim, uma área de ";

        texto_perimetro = texto_perimetro.toUpperCase() + imovel.getDimensoes().getAreaTerreno() + " m² (";
        texto_perimetro += extensoInteiro.toString().toUpperCase();
        texto_perimetro += (extensoDecimalString + "metros quadrados)" + " e um perímetro de ").toUpperCase();
        texto_perimetro += imovel.getPerimeField().trim().replace("m", " m") + " (" + extensoPerimetro.toString().toUpperCase() + " metros ".toUpperCase() + centimetros.toUpperCase() + ").";

        imovel.setPerimetroField(texto_perimetro);
        imovel.setTexto_descricao_perimetro("Descrição Perímetro");
    }
}
